package forum.server.controller;

import java.io.File;

import org.compass.core.Compass;
import org.compass.core.CompassHit;
import org.compass.core.CompassHits;
import org.compass.core.CompassSession;
import org.compass.core.config.CompassConfiguration;
import org.compass.core.config.CompassConfigurationFactory;

import forum.server.domain.Post;
import forum.server.exceptions.InvalidSearchRangeException;
import forum.server.exceptions.NoSuchUserException;

/**
 * The class acts as an adapter to the search engine interface,
 * using compass as an adaptee.
 * The class is singelton.
 * @author Alon Furman
 */
public class SearchAdapter implements SearchEngine {

	private static SearchAdapter instance = null;
	//adaptee
	private Compass compass;
	
	/**
	 * Constructor
	 */
	private SearchAdapter(){
		File file = new File("compassSettings.xml");
        CompassConfiguration conf = CompassConfigurationFactory
                .newConfiguration().configure(file);               

        compass = conf.buildCompass();
	}
	
	public static SearchAdapter getInstance(){
		if (instance == null){
			instance = new SearchAdapter();
		}
		return instance;
	}
	
	/**
	 * Adds the post p to the search engine.
	 * @param p The post which we want to add to the search engine database.
	 */
	@Override
	public void addData(Post p) {
		CompassSession session = compass.openSession();
		session.save(p);
		session.close();
	}

	/**
	 * Removes a post p from the search database.
	 * @param p - The post to remove from search engine database.
	 */
	@Override
	public void removeData(Post p) {
		CompassSession session = compass.openSession();
		session.delete(p);
		session.close();
	}

	/**
	 * Performs a search by author username, returns results from index "from"
	 * up to index "to".
	 * @param username - The author's username.
	 * @param from - from index
	 * @param to - to index
	 * @return - Array of search hits.
	 */
	@Override
	public SearchHit[] searchByAuthor(String username, int from, int to)
			throws NoSuchUserException, InvalidSearchRangeException {
		//System.out.println("Search by author initiated.");
		if (to < from) {
			throw new InvalidSearchRangeException("cannot return "+(to-from)+" results");
		}
		CompassSession session = compass.openSession();
		CompassHits hits = session.find("author: "+username);
		if (hits.length()==0){
			throw new NoSuchUserException(username+" is not a valid username, or the user did not publish any posts.");
		}
        CompassHit[] detachedHits = hits.detach(from, to).getHits();
        SearchHit[] results = new SearchHit[detachedHits.length];
        for (int i = 0; i < detachedHits.length; i++) {
            Post foundPost = (Post)(detachedHits[i].data());
            results[i] = new SearchHit(foundPost, detachedHits[i].getScore());
        }
        session.close();
		return results;
	}

	/**
	 * Performs a search of post content matching the given phrase, returns results
	 * from index "from" to index "to".
	 * @param phrase - the prase to search for.
	 * @param from - from index
	 * @param to - to index
	 * @return - Array of search hits.
	 */
	@Override
	public SearchHit[] searchByContent(String phrase, int from, int to)
			throws InvalidSearchRangeException {
		if (to < from) {
			throw new InvalidSearchRangeException("cannot return "+(to-from)+" results");
		}
		CompassSession session = compass.openSession();
		CompassHits hits = session.find("content:"+phrase);
        CompassHit[] detachedHits = hits.detach(from, to).getHits();
        SearchHit[] results = new SearchHit[detachedHits.length];
        for (int i = 0; i < detachedHits.length; i++) {
            Post foundPost = (Post)(detachedHits[i].data());
            results[i] = new SearchHit(foundPost, detachedHits[i].getScore());
        }
        session.close();
		return results;
	}

}
